package com.simpou.commons.utils.string;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.StringTokenizer;

/**
 * Operações sobre texto.
 *
 * @author Jonas Pereira
 * @since 2011-06-25
 */
public final class Strings {

    /**
     * Texto adicionado no final de uma string truncada.
     */
    public static final String SUFIX_TEXT_TRUNC = "...";

    /**
     * <p>isEmpty.</p>
     *
     * @param string String.
     * @return True se null ou vazio ou somente espaços.
     */
    public static boolean isEmpty(final String string) {
        return (string == null) || string.replaceAll(" ", "").equals("");
    }

    /**
     * Substitui parâmetros num texto. Parâmetros são do tipo {0},{1}...{n}.
     *
     * @param text Text contendo tags {0},{1},...
     * @param params Parâmetros.
     * @return Novo texto.
     */
    public static String replaceParams(final String text, final String... params) {
        return replaceParams(text, (Object[]) params);
    }

    /**
     * Substitui parâmetros num texto. Parâmetros são do tipo {0},{1}...{n}.
     *
     * @param text Text contendo tags {0},{1},...
     * @param params Parâmetros.
     * @return Novo texto.
     */
    public static String replaceParams(final String text, final Object... params) {
        if ((text == null) || text.isEmpty()) {
            return text;
        }

        return MessageFormat.format(text, params);
    }

    /**
     * <p>toUpperCaseFirstLetter.</p>
     *
     * @param text Texto.
     * @return Texto com a primeira letra maiúscula de cada palavra separada por
     * espaço.
     */
    public static String toUpperCaseFirstLetter(final String text) {
        if ((text == null) || isEmpty(text)) {
            return text;
        }

        final String delim = " ";
        StringTokenizer tokenizer = new StringTokenizer(text, delim, true);

        String first;
        StringBuilder textUpperBuilder = new StringBuilder();

        String word;

        while (tokenizer.hasMoreElements()) {
            word = tokenizer.nextToken();

            if (word.equals(delim)) {
                textUpperBuilder.append(delim);
            } else {
                first = word.charAt(0) + "";
                textUpperBuilder.append(first.toUpperCase())
                        .append(word.substring(1));
            }
        }

        return textUpperBuilder.toString();
    }

    /**
     * <p>toLowerCaseFirstLetter.</p>
     *
     * @param text Texto.
     * @return Texto com a primeira letra maiúscula de cada palavra separada por
     * espaço.
     */
    public static String toLowerCaseFirstLetter(final String text) {
        if ((text == null) || isEmpty(text)) {
            return text;
        }

        final String delim = " ";
        StringTokenizer tokenizer = new StringTokenizer(text, delim, true);

        String first;
        StringBuilder textLowerBuilder = new StringBuilder();

        String word;

        while (tokenizer.hasMoreElements()) {
            word = tokenizer.nextToken();

            if (word.equals(delim)) {
                textLowerBuilder.append(delim);
            } else {
                first = word.charAt(0) + "";
                textLowerBuilder.append(first.toLowerCase())
                        .append(word.substring(1));
            }
        }

        return textLowerBuilder.toString();
    }

    /**
     * <p>trunc.</p>
     *
     * @param string String.
     * @param chars Número máximo de caracteres (primeiros).
     * @return String truncada.
     */
    public static String trunc(final String string, final int chars) {
        if (string.length() > chars) {
            return string.substring(0, chars) + SUFIX_TEXT_TRUNC;
        } else {
            return string;
        }
    }

    /**
     * Concatena uma string ao final de outra caso a segunda já não a contenha
     * em seu final.
     *
     * @param string String a ser modificada.
     * @param append String a ser adcionada ao fim caso já não esteja presente.
     * @return Nova string.
     */
    public static String appendAtEndIfNotContains(final String string,
            final String append) {
        String newString = string;

        if (!string.endsWith(append)) {
            newString += append;
        }

        return newString;
    }

    /**
     * Concatena uma string ao início de outra caso a segunda já não a contenha
     * em seu início.
     *
     * @param string String a ser modificada.
     * @param append String a ser adcionada no início caso já não esteja
     * presente.
     * @return Nova string.
     */
    public static String appendAtBeginIfNotContains(final String string,
            final String append) {
        String newString = string;

        if (!string.startsWith(append)) {
            newString = append + newString;
        }

        return newString;
    }

    /**
     * Retira os caracteres de retorno de linha, mudança de linha, tabulações e
     * espaços de uma string.
     *
     * @param string String.
     * @return String sem formatação ou null caso string seja null.
     */
    public static String unformat(final String string) {
        if(string == null){
            return null;
        }
        return string.replaceAll(" ", "").replaceAll("\r", "").replaceAll("\n", "").replaceAll("\t", "");
    }

    /**
     * @param is Stream contendo uma string.
     * @return String extraída.
     * @throws java.io.IOException Problemas ao ler stream.
     */
    public static String extract(final InputStream is, final String charset) throws IOException {
        final StringBuilder stringBuilder = new StringBuilder();
        final BufferedReader br = new BufferedReader(
                new InputStreamReader(is, charset)
        );
        try {
            final int bufferSize = 128;
            final char[] charBuffer = new char[bufferSize];
            int bytesRead;
            while ((bytesRead = br.read(charBuffer)) > 0) {
                stringBuilder.append(charBuffer, 0, bytesRead);
            }
        } finally {
            br.close();
        }

        return stringBuilder.toString();
    }

}
